﻿using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace NougakudoCompanion.Commons
{
    static internal class TableStorageHelper
    {
        static CloudTableClient client;
        static string tableName;
        static TableServiceContext context;

        /// <summary>
        /// Get a TableServiceContext. If not exsits a table, create new table.
        /// </summary>
        /// <returns></returns>
        static Tuple<bool, string> SetTable()
        {
            TableStorageHelper.tableName = RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_CONTAINER);
            CloudStorageAccount account = null;
            //var useDevelopmentFabric = bool.Parse(RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_DEVLOPMENTFABRIC));
            var useDevelopmentFabric = RoleEnvironment.IsEmulated;  // Add for Azure SDK 1.5.
            if (useDevelopmentFabric)
            {
                account = CloudStorageAccount.DevelopmentStorageAccount;
            }
            else
            {
                account = new CloudStorageAccount(
                               new StorageCredentialsAccountAndKey(RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_ACCOUNT),
                                                                   RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_SHAREDKEY)), false);
            }
            try
            {
                client = account.CreateCloudTableClient();

                client.CreateTableIfNotExist(tableName);
                context = client.GetDataServiceContext();
                return new Tuple<bool, string>(true, "");
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Insert or Update a role instance data to table. 
        /// </summary>
        /// <param name="instanceID">Role instance id</param>
        /// <param name="machineName">Machine Name</param>
        /// <returns></returns>
        static internal Tuple<bool, string> SetInstance(string instanceID, string machineName)
        {
            try
            {
                var instancesResult = GetInstnaces();
                if (!instancesResult.Item1)
                    return new Tuple<bool, string>(instancesResult.Item1, instancesResult.Item2);
                CompanionInstance entity;
                var entities = instancesResult.Item3.Where(x => x.PartitionKey == Constants.NOUGAKUDO_NAME && x.RowKey == instanceID);
                if (entities.Count() == 0)
                {
                    entity = new CompanionInstance(instanceID) { MachineName = machineName };
                    context.AddObject(tableName, entity);
                }
                else
                {
                    entity = entities.First();
                    entity.MachineName = machineName;
                    context.UpdateObject(entity);
                }
                context.SaveChanges();
                return new Tuple<bool, string>(true, "");
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Delete a role instance data from table.
        /// </summary>
        /// <param name="instanceID">Role instance id.</param>
        /// <returns></returns>
        static internal Tuple<bool, string> DeleteInstance(string instanceID)
        {

            try
            {
                var instancesResult = GetInstnaces();
                if (!instancesResult.Item1)
                    return new Tuple<bool, string>(instancesResult.Item1, instancesResult.Item2);
                CompanionInstance entity;
                var entities = instancesResult.Item3.Where(x => x.PartitionKey == "NougakuDoCompanion" && x.RowKey == instanceID);
                if (entities.Count() != 0)
                {
                    entity = entities.First();
                    context.DeleteObject(entity);
                }
                context.SaveChanges();
                return new Tuple<bool, string>(true, "");
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Get role instances data from table.
        /// </summary>
        /// <returns>bool, error message, instances data</returns>
        static internal Tuple<bool, string, List<CompanionInstance>> GetInstnaces()
        {
            var ret = SetTable();
            if (!ret.Item1) return new Tuple<bool, string, List<CompanionInstance>>(ret.Item1, ret.Item2, null);
            try
            {
                var entities = context.CreateQuery<CompanionInstance>(tableName);

                return new Tuple<bool, string, List<CompanionInstance>>(true, "", entities.ToList());
            }
            catch (Exception e)
            {
                // When execute query as TableServiceContext.CreateQuery, if no data as 404(not found) then 
                // return 404 as DataServiceQueryException.Response.StatusCode.
                return new Tuple<bool,string,List<CompanionInstance>>(false, e.Message, null);
            }
        }

    }

    /// <summary>
    /// Role instance data class.
    /// PartitionKey = NougakuDo, RowKey = Role instance id
    /// </summary>
    public class CompanionInstance : TableServiceEntity
    {
        public CompanionInstance(string instanceId)
        {
            PartitionKey = Constants.NOUGAKUDO_NAME;
            RowKey = instanceId;
        }

        public CompanionInstance() : base() { }

        public string MachineName { get; set; }

    }
}
